/*---------------------------------------------------------------------------------------
Filename: app-android.c
Description: JNI Wrapper for droidViz

Copyright (c) 2010, droidViz Project Maintainers
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------------------*/
#include <jni.h>
#include <sys/time.h>
#include <time.h>
#include <android/log.h>
#include <stdint.h>
#include <stdio.h>
#include "app.h"

int   gAppAlive   = 1;

static int  sWindowWidth  = 320;
static int  sWindowHeight = 480;
static int  sDemoStopped  = 0;
static long sTimeOffset   = 0;
static int  sTimeOffsetInit = 0;
static long sTimeStopped  = 0;

static long
_getTime(void)
{
    struct timeval  now;

    gettimeofday(&now, NULL);
    return (long)(now.tv_sec*1000 + now.tv_usec/1000);
}

/* Call to initialize the graphics state */
JNIEXPORT jint JNICALL
Java_com_rcos_droidViz_DroidVizRenderer_DroidVizInit( JNIEnv*  env )
{
    importGLInit();
    if( !appInit() )
    {
      errprintf( "Could not initialize droidViz." );
      return;
    }
    gAppAlive    = 1;
    sDemoStopped = 0;
    sTimeOffsetInit = 0;
}

JNIEXPORT jint JNICALL
Java_com_rcos_droidViz_DroidVizRenderer_DroidVizResize( JNIEnv*  env, jobject  thiz, jint w, jint h )
{
	long   curTime;
    sWindowWidth  = w;
    sWindowHeight = h;

    __android_log_print(ANDROID_LOG_INFO, "DroidViz", "resize w=%d h=%d", w, h);
}

/* Call to finalize the graphics state */
JNIEXPORT jint JNICALL
Java_com_rcos_droidViz_DroidVizRenderer_DroidVizDone( JNIEnv*  env )
{
    appDeinit();
    importGLDeinit();
}

/* This is called to indicate to the render loop that it should
 * stop as soon as possible.
 */
JNIEXPORT jint JNICALL
Java_com_rcos_droidViz_DroidVizRenderer_DroidVizPause( JNIEnv*  env )
{
    sDemoStopped = !sDemoStopped;
    if (sDemoStopped) {
        /* we paused the animation, so store the current
         * time in sTimeStopped for future nativeRender calls */
        sTimeStopped = _getTime();
    } else {
        /* we resumed the animation, so adjust the time offset
         * to take care of the pause interval. */
        sTimeOffset -= _getTime() - sTimeStopped;
    }
	
	// DroidViz - - - -IMPORTANTIMPORTANTIMPORTANT
	// Hardware buffers become invalid after a pause.  We'll need to 
	// forget and re-create the hardware buffers here.
}

/* Call to render the next GL frame */
JNIEXPORT jint JNICALL
Java_com_rcos_droidViz_DroidVizRenderer_DroidVizRender( JNIEnv*  env )
{
    long   curTime;

    /* NOTE: if sDemoStopped is TRUE, then we re-render the same frame
     *       on each iteration.
     */
    if (sDemoStopped) {
        curTime = sTimeStopped + sTimeOffset;
    } else {
        curTime = _getTime() + sTimeOffset;
        if (sTimeOffsetInit == 0) {
            sTimeOffsetInit = 1;
            sTimeOffset     = -curTime;
            curTime         = 0;
        }
    }

    //__android_log_print(ANDROID_LOG_INFO, "droidViz", "curTime=%ld", curTime);

    appRender(curTime, sWindowWidth, sWindowHeight);
}

JNIEXPORT jint JNICALL
Java_com_rcos_droidViz_DroidVizRenderer_DroidVizDensityLocation( JNIEnv*  env, jobject  thiz, jint mouse_xloc, jint mouse_yloc )
{
	AddDensity(mouse_xloc, mouse_yloc);
	//dprintf(0,"\nX Location%d Y Location %d.\n", mouse_xloc, mouse_yloc); 
}

JNIEXPORT jint JNICALL
Java_com_rcos_droidViz_DroidVizRenderer_DroidVizVertexShader( JNIEnv* env, jobject obj, jstring filename )
{
	// String for the Vertex Shader from JAVA level
	const char *mfile;
	char *cFile; // Char array of Shader
	long lFileLen;
	int count;

	// Used to prevent garbage collection
	mfile = (*env)->GetStringUTFChars(env,filename, NULL);
	dprintf(0,"Filename: %s",mfile);

	if (strcmp(mfile,"preset") == 0)
	{
	dprintf(0,"Preset One Chosen: %s",mfile);
	SetVertexShaderPreset();
	}

	else{

	if (!mfile) return -1;
	dprintf(0,"mfile ok\n");

	FILE* file = fopen(mfile,"r");

    if (file != NULL)
    {
		fseek(file, 0L, SEEK_END);					 // position to end of file 
        lFileLen = ftell(file);						 // get file length 
        rewind(file);								 // back to start of file 
		cFile = calloc(lFileLen + 1, sizeof(char));  //allocate memory for unknown file size 
		if(cFile == NULL) 
        { 
		    // Error Checking
			dprintf(0,"\nInsufficient memory to read file.\n"); 
        }
		if (fread(cFile, lFileLen, 1, file) != 1) 
        {
			// Error Checking
            dprintf(0, "error reading file.\n"); 
        } 
                                                                                                                                                                                                                               
        //Print File Contents for Debugging                                                                                                                                                                                                                             
        //for (count = 0; count < lFileLen; count++){ 
        //dprintf(0,"%c", cFile[count]);
        //}                        
        fflush(file);
        fclose(file);
    }
	
	SetVertexShader(cFile);
	}
	(*env)->ReleaseStringUTFChars(env,filename,mfile);
}
JNIEXPORT jint JNICALL
Java_com_rcos_droidViz_DroidVizRenderer_DroidVizFragmentShader( JNIEnv* env, jobject obj, jstring filename )
{
	// String for the Vertex Shader from JAVA level
	const char *mfile;
	char *cFile; // Char array of Shader
	long lFileLen;
	int count;

	// Used to prevent garbage collection
	mfile = (*env)->GetStringUTFChars(env,filename, NULL);
	dprintf(0,"Filename: %s",mfile);

	if(strcmp(mfile,"preset") == 0)
	{
	dprintf(0,"Preset One Chosen: %s",mfile);
	SetFragmentShaderPreset();
	}
	else
	{

	if (!mfile) return -1;
	dprintf(0,"mfile ok\n");

	FILE* file = fopen(mfile,"r");

    if (file != NULL)
    {
		fseek(file, 0L, SEEK_END);					 // position to end of file 
        lFileLen = ftell(file);						 // get file length 
        rewind(file);								 // back to start of file 
		cFile = calloc(lFileLen + 1, sizeof(char));  //allocate memory for unknown file size 
		if(cFile == NULL) 
        { 
		    // Error Checking
			dprintf(0,"\nInsufficient memory to read file.\n"); 
        }
		if (fread(cFile, lFileLen, 1, file) != 1) 
        {
			// Error Checking
            dprintf(0, "error reading file.\n"); 
        } 
                                                                                                                                                                                                                                  
        //Print File Contents for Debugging                                                                                                                                                                                                                             
        //for (count = 0; count < lFileLen; count++){ 
        //dprintf(0,"%c", cFile[count]);
        //}                        
        fflush(file);
        fclose(file);
    }

	SetFragmentShader(cFile);
	}
	(*env)->ReleaseStringUTFChars(env,filename,mfile);
}

JNIEXPORT jint JNICALL
Java_com_rcos_droidViz_DroidVizRenderer_DroidVizChangeShader( JNIEnv* env, jobject obj, jint shader_code )
{
	changeShader_helper(shader_code);
}